package com.stanford.data;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.stanford.ml.naivebayes.Attribute;
import com.stanford.ml.naivebayes.ClassLabel;
import com.stanford.ml.naivebayes.Instance;

/**
 * User is a data container for each line in the data files
 * 
 * @author Fatih Sunor
 *
 */
public class User implements Instance{

	private static final double NONE = 0.0;
	private static final double SOME = 1.0;
	private static final double INTERESTED = 2.0;
	private static final double FAN = 3.0;
	
	private int _rating;
	private Date _timeStamp;
	private int _age;
	private int _gender;
	private String _city;
	private String _state;
	private String _country;
	private Map<String,Integer> _tags;
	
	/**
	 * Constructor that initializes all the fields except the tag map to keep
	 * the fields immutable.
	 * @param rating is user's appreciation of the content represented by 1
	 * for positive -1 for negative and neutral 0
	 * @param timeStamp is a Date when the visit happened in milliseconds
	 * @param age is user's age
	 * @param gender is user's gender
	 * @param city is user's city
	 * @param state is user's state
	 * @param country is user's country
	 */
	public User(int rating, Date timeStamp, int age, 
			int gender, String city, String state, String country){
		_rating = rating;
		_timeStamp = timeStamp;
		_age = age;
		_gender = gender;
		_city = city;
		_state = state;
		_country = country;
		_tags = new HashMap<String, Integer>();
	}
	
	/**
	 * appendTag populates new tag information as it's available, while keeping 
	 * tags immutable
	 * @param tag is a topic user preferred to define a content, e.g. "american-football"
	 * @param count is how many times the particular tag is used by the user e.g. 21
	 */
	public void appendTag(String tag, int count){
		_tags.put(tag, count);
	}
	
	/**
	 * @return the rating
	 */
	public int getRating() {
		return _rating;
	}

	/**
	 * @return the timeStamp
	 */
	public Date getTimeStamp() {
		return _timeStamp;
	}

	/**
	 * @return the age
	 */
	public int getAge() {
		return _age;
	}

	/**
	 * @return the gender
	 */
	public int getGender() {
		return _gender;
	}

	/**
	 * @return the city
	 */
	public String getCity() {
		return _city;
	}

	/**
	 * @return the state
	 */
	public String getState() {
		return _state;
	}

	/**
	 * @return the country
	 */
	public String getCountry() {
		return _country;
	}

	/**
	 * @return the tags
	 */
	public Map<String, Integer> getTags() {
		return _tags;
	}

	/**
	 * Return attributes of the user by normalizing/clustering
	 * tagging information
	 * @return Attribute[]
	 */
	public Attribute[] getAttributes(Map<String, Integer> tagMax) {
		List<Attribute> attributes = new ArrayList<Attribute>();
		Attribute timeStamp = new Attribute("TimeStamp", _timeStamp.toString());
		attributes.add(timeStamp);
		Attribute age = new Attribute("Age", Integer.toString(_age));
		attributes.add(age);
		Attribute gender = new Attribute("Gender", _gender);
		attributes.add(gender);
		Attribute city = new Attribute("City", _city);
		attributes.add(city);
		Attribute state = new Attribute("State", _state);
		attributes.add(state);
		Attribute country = new Attribute("Country", _country);
		attributes.add(country);
		for(String tag: _tags.keySet()){
			attributes.add(new Attribute(tag, interest(tag, _tags.get(tag),tagMax)));
		}
		return DataUtil.attributeListToArray(attributes);
	}

	private String interest(String tag, Integer tagCount, Map<String, Integer> tagMax) {
		if(tagCount == 0){
			return Double.toString(NONE);
		}
		double interestRatio = (double)tagCount/(double)tagMax.get(tag);
		if(interestRatio < (double)2/(double)3){
			if(interestRatio < (double)1/(double)3){
				return Double.toString(SOME);
			}
			return Double.toString(INTERESTED);
		}
		return Double.toString(FAN);
	}

	/**
	 * Returns a class label based on the rating 
	 */
	public ClassLabel getClassLabel() {
		ClassLabel label = new ClassLabel(Integer.toString(_rating));
		return label;
	}

	/**
	 * Returns the tag attributes without any clustering
	 * @return an Attribute[]
	 */
	public Attribute[] getAttributesWithNominalTag() {
		List<Attribute> attributes = new ArrayList<Attribute>();
		Attribute timeStamp = new Attribute("TimeStamp", _timeStamp.toString());
		attributes.add(timeStamp);
		Attribute age = new Attribute("Age", Integer.toString(_age));
		attributes.add(age);
		Attribute gender = new Attribute("Gender", _gender);
		attributes.add(gender);
		Attribute city = new Attribute("City", _city);
		attributes.add(city);
		Attribute state = new Attribute("State", _state);
		attributes.add(state);
		Attribute country = new Attribute("Country", _country);
		attributes.add(country);
		for(String tag: _tags.keySet()){
			attributes.add(new Attribute(tag, _tags.get(tag)));
		}
		return DataUtil.attributeListToArray(attributes);
	}
	
}